package clem;

import java.util.ArrayList;
import java.util.List;

import javax.swing.DefaultCellEditor;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;

import org.apache.commons.beanutils.PropertyUtils;

public class BeanTable<T> extends JTable {
  private static final long serialVersionUID = 1L;
  private final List<T> elencoDati;
  private final List<ColumnProperties<?>> columnsProperties= new ArrayList<ColumnProperties<?>>();
  
  private class ColumnProperties<K> {
    public final String columnName;
    public final Class<K> columnType;
    public final boolean readOnly;
    public final TableCellEditor columnEditor;
    public final TableCellRenderer columnRenderer;
    public final String propertyName;
    
    public ColumnProperties(String columnName, Class<K> columnType, boolean readOnly, TableCellEditor columnEditor, TableCellRenderer columnRenderer,
        String propertyName) {
      super();
      this.columnName = columnName;
      this.columnType = columnType;
      this.readOnly = readOnly;
      this.columnEditor = columnEditor;
      this.columnRenderer = columnRenderer;
      this.propertyName = propertyName;
    }
    
    public K getValueFromPropety(T t) {
      if (t == null)
        return null;
      try {
        K k = (K) PropertyUtils.getProperty(t, propertyName);
        return k;
      } catch (Exception e) {
        throw new RuntimeException("Errore durante l'accesso alla propreta'" + propertyName, e);
      }
      
    }
    
    public void updatePropety(T t,Object k) {
      if (t == null) return;
      try {
        PropertyUtils.setProperty(t, propertyName,(K)k);
      } catch (Exception e) {
        throw new RuntimeException("Errore durante l'accesso alla propreta'" + propertyName, e);
      }
      
    }    
  }  

  class BeanTableModel extends AbstractTableModel{

    private static final long serialVersionUID = 1L;

    @Override
    public int getColumnCount() {
      return columnsProperties.size();
    }
    
    @Override
    public int getRowCount() {
      return elencoDati.size();
    }
    
    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
      if (elencoDati == null || elencoDati.size() <= rowIndex)
        return null;
      T t = elencoDati.get(rowIndex);
      return columnsProperties.get(columnIndex).getValueFromPropety(t);
    }
    
    @Override
    public Class<?> getColumnClass(int columnIndex) {
      return columnsProperties.get(columnIndex).columnType;
    }
    
    @Override
    public String getColumnName(int column) {
      return columnsProperties.get(column).columnName;
    }
    
    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
      return !columnsProperties.get(columnIndex).readOnly;
    }
    
    @Override
    public void setValueAt(Object value, int rowIndex, int columnIndex) {
      if (elencoDati == null || elencoDati.size() <= rowIndex)
        return;
      T t = elencoDati.get(rowIndex);
      columnsProperties.get(columnIndex).updatePropety(t, value);
    }    
  };
  
  public BeanTable(List<T> elencoDati) {
    super();
    this.elencoDati = elencoDati;
  }
  
  
  public <K> void addBeanColumn(String columnName, Class<K> columnType, String propertyName, boolean readOnly, TableCellEditor columnEditor,
      TableCellRenderer columnRenderer) {
    columnsProperties.add(new ColumnProperties<K>(columnName, columnType, readOnly, columnEditor, columnRenderer, propertyName));
  }
  
  public <K> void addBeanColumn(String columnName, Class<K> columnType,String propertyName) {
    columnsProperties.add(new ColumnProperties<K>(columnName, columnType, true, new DefaultCellEditor(new JTextField()), new DefaultTableCellRenderer(), propertyName));
  }
  
  public <K> void addBeanColumn(String columnName, Class<K> columnType,String propertyName, boolean readOnly) {
    columnsProperties.add(new ColumnProperties<K>(columnName, columnType, readOnly, new DefaultCellEditor(new JTextField()), new DefaultTableCellRenderer(), propertyName));
  }
  
  public void updateModel(){
    setModel(new BeanTableModel());
  }
  
  
}
